`timescale 1ns / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:
//
// Create Date:   15:30:05 05/05/2012
// Design Name:   cache
// Module Name:   C:/achdmips/trunk/hdl/L2Cache/CacheTest.v
// Project Name:  L2Cache
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: cache
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
////////////////////////////////////////////////////////////////////////////////

module CacheTest;

	// Inputs
	reg clk;
	reg noncache;
	reg up_rd;
	reg up_wr;
	reg [3:0] up_mask;
	reg [31:0] up_addr;
	reg [31:0] up_din;
	reg [31:0] dn_din;
	reg dn_dinok;

	// Outputs
	wire query_done;
	wire [31:0] up_dout;
	wire up_doutok;
	wire dn_rd;
	wire dn_wr;
	wire [3:0] dn_mask;
	wire [31:0] dn_addr;
	wire [31:0] dn_dout;

	// Instantiate the Unit Under Test (UUT)
	cache uut (
		.clk(clk), 
		.noncache(noncache),
		.query_done(query_done),
		.up_rd(up_rd), 
		.up_wr(up_wr), 
		.up_mask(up_mask), 
		.up_addr(up_addr), 
		.up_din(up_din), 
		.up_dout(up_dout), 
		.up_doutok(up_doutok), 
		.dn_rd(dn_rd), 
		.dn_wr(dn_wr), 
		.dn_mask(dn_mask), 
		.dn_addr(dn_addr), 
		.dn_din(dn_din), 
		.dn_dout(dn_dout), 
		.dn_dinok(dn_dinok)
	);

	reg ready = 0;
	initial begin
		// Initialize Inputs
		clk = 0;
		noncache = 0;
		up_rd = 0;
		up_wr = 0;
		up_mask = 0;
		up_addr = 0;
		up_din = 0;
		dn_din = 0;
		dn_dinok = 0;

		// Wait 100 ns for global reset to finish
		#100;
        
		ready = 1;
	end
	
	// Clock generator
	always begin
		#5;
		clk = ready;
		#5;
		clk = 0;
		if(ready)
			$display("--- CLOCK ---");
	end
	
	// Request Generator
	reg[15:0] testcount = 0;
	always @(posedge clk) begin
		
		up_addr <= 0;
		up_rd <= 0;
		up_wr <= 0;
		up_din <= 0;
		up_mask <= 0;
		noncache <= 0;
		
		case(testcount)
			
			// Word write to an uncached address
			0: begin
				up_addr <= 32'hb0000104;
				up_wr <= 1;
				up_din <= 32'hdeadbeef;
				up_mask <= 4'b1111;
				testcount <= 1;
			end
			
			// Word write to a cached address
			1: begin
				up_addr <= 32'h90000000;
				up_wr <= 1;
				up_din <= 32'hbaadc0de;
				up_mask <= 4'b1111;
				testcount <= 2;
			end
			
			// Word read from an uncached address
			2: begin 
				up_addr <= 32'hb0000104;
				up_rd <= 1;
				testcount <= 3;
			end
			
			// Word read from a cached address (hit)
			3: begin
				up_addr <= 32'h90000000;
				up_rd <= 1;
				testcount <= 4;
			end
			
			4: begin
				// Verify read in test case 2 worked
				if(up_doutok && up_dout == 32'h4ffffefb)
					$display("Uncached Read Test Passed");
				else
					$display("Uncached Read Test Failed");
				
				// Write and perform a cache hit
				up_addr <= 32'h91000000;
				up_wr <= 1;
				up_din <= 32'hfeedface;
				up_mask <= 4'b1111;
				
				testcount <= 5;
			end
			
			5: begin
				// Verify read in test case 3 worked
				if(up_doutok && up_dout == 32'hbaadc0de)
					$display("Cached Read Test Passed");
				else
					$display("Cached Read Test Failed. up_doutok: 0b%b, up_dout: 0x%x", up_doutok, up_dout);
					
				// Read from the original address which should miss
				up_addr <= 32'h90000000;
				up_rd <= 1;
				
				testcount <= 6;
			end
			
			// Wait for the read
			6: begin
				testcount <= 7;
			end
			
			7: begin
				
				// Cache hit?
				if(up_doutok) begin
					if(up_dout == 32'h6fffffff)
						$display("Cache Hit, Cached Read Test Success");
					else
						$display("Cache Hit, but Cached Read Test Failed.  Expected 0x%x, but got 0x%x", 32'h6fffffff, up_dout);
					testcount <= 8;
				end
				
				else begin
					$display("Cache Miss, reissuing read request");
					up_addr <= 32'h90000000;
					up_rd <= 1;
					testcount <= 6;
				end
			end
			
			// Noncache read of data from test case 3
			8: begin
				noncache <= 1;
				up_addr <= 32'h90000000;
				up_rd <= 1;
				testcount <= 9;
			end
			
			// Wait for the read
			9: begin
				testcount <= 10;
			end
			
			// Verify noncache read hit
			10: begin
				if(up_doutok)
					$display("Passed: Data in cache at requested address: 0x%x", up_dout);
				else
					$display("Failed: Noncache Read Miss should have Hit: 0b%b", up_doutok);
				testcount <= 11;
			end
			
			// Perform a noncache read which should miss
			11: begin
				noncache <= 1;
				up_addr <= 32'h91000000;
				up_rd <= 1;
				testcount <= 12;
			end
			
			// Wait for read
			12: begin
				testcount <= 13;
			end
			
			// Verify noncache read miss
			13: begin
				if(up_doutok)
					$display("Failed: Noncache Read hit, but should have missed.  Returning data 0x%x", up_dout);
				else
					$display("Passed: Noncache Read Miss.");
				testcount <= 14;
			end
			
			// Stall
			14: begin
			end
				
		endcase
	end
	
	// Fake a downstream module
	always @(posedge clk) begin
		dn_din <= 0;
		dn_dinok <= 0;
		
		if(dn_wr) begin
			$display("[Downstream] Writing 0x%x to address 0x%x wmask %b", dn_dout, dn_addr, dn_mask);
		end
		
		if(dn_rd) begin
			$display("[Downstream] Reading from address 0x%x, returning 0x%x", dn_addr, ~dn_addr);
			dn_din <= ~dn_addr;
			dn_dinok <= 1;
		end
	end
      
endmodule

